#ifndef __WM_SSPI_H__
#define __WM_SSPI_H__

#include "wm_hal.h"

#define SSPI	((SSPI_TypeDef *)SSPI_BASE)

#define SSDIO	((SSDIO_TypeDef *)SSDIO_BASE)

#define WRAPPER ((WRAPPER_TypeDef *)WRAPPER_BASE)

// 如果SSPI_TXBUF_DESC_NUM、SSPI_RXBUF_DESC_NUM改大，
// 那么对应的ld文件中__heap_end地址就需要向前移动，以防
// 内存使用过大导致占用SSPI的内存
#define SSPI_TXBUF_DESC_NUM		2						
#define SSPI_RXBUF_DESC_NUM		3
#define SSPI_TXBUF_NUM			SSPI_TXBUF_DESC_NUM
#define SSPI_RXBUF_NUM			SSPI_RXBUF_DESC_NUM

#define SSPI_TXBUF_SIZE			1500
#define SSPI_RXBUF_SIZE			1500

#define SSPI_CMD_RXBUF_SIZE		256
#define SSPI_CIS_SIZE			128

extern unsigned int __heap_end;
#define SSPI_SSDIO_ADDR ((unsigned int)(&__heap_end))

#define SSPI_TX_DESC_SIZE	sizeof(struct TxBufDesc)
#define SSPI_RX_DESC_SIZE	sizeof(struct RxBufDesc)

#define SSPI_TXBUF_BASE_ADDR		((uint32_t)(SSPI_SSDIO_ADDR))
#define SSPI_TXBUF_TOTAL_SIZE		(SSPI_TXBUF_NUM * SSPI_TXBUF_SIZE)
#define SSPI_TX_DESC_BASE_ADDR		((uint32_t)(SSPI_TXBUF_BASE_ADDR + SSPI_TXBUF_TOTAL_SIZE))
#define SSPI_TX_DESC_TOTAL_SIZE		(SSPI_TX_DESC_SIZE * SSPI_TXBUF_DESC_NUM)
#define SSPI_RXBUF_BASE_ADDR		((uint32_t)(SSPI_TX_DESC_BASE_ADDR + SSPI_TX_DESC_TOTAL_SIZE))
#define SSPI_RXBUF_TOTAL_SIZE		(SSPI_RXBUF_NUM * SSPI_RXBUF_SIZE)
#define SSPI_RX_DESC_BASE_ADDR		((uint32_t)(SSPI_RXBUF_BASE_ADDR + SSPI_RXBUF_TOTAL_SIZE))
#define SSPI_RX_DESC_TOTAL_SIZE		(SSPI_RX_DESC_SIZE * SSPI_RXBUF_DESC_NUM)
#define SSPI_CMD_RXBUF_ADDR			((uint32_t)(SSPI_RX_DESC_BASE_ADDR + SSPI_RX_DESC_TOTAL_SIZE))

#define SSDIO_CIS0_ADDR				(SSPI_CMD_RXBUF_ADDR + SSPI_CMD_RXBUF_SIZE)
#define SSDIO_CIS1_ADDR				(SSDIO_CIS0_ADDR + SSPI_CIS_SIZE)

#define CIS_FUN0_ADDR				((uint32_t)SSDIO_CIS0_ADDR)
#define CIS_FUN1_ADDR				((uint32_t)SSDIO_CIS1_ADDR)

#define FN0_TPL_FUNCID				(CIS_FUN0_ADDR + 0x00)
#define FN0_TPL_FUNCE				(CIS_FUN0_ADDR + 0x04)
#define FN0_TPL_FUNCE_MAXBLK		(CIS_FUN0_ADDR + 0x08)
#define FN0_TPL_MANFID_MID		    (CIS_FUN0_ADDR + 0x0C)
#define FN0_TPL_END					(CIS_FUN0_ADDR + 0x10)

#define FN1_TPL_FUNCID				(CIS_FUN1_ADDR + 0x00)
#define FN1_TPL_FUNCE				(CIS_FUN1_ADDR + 0x04)
#define FN1_TPL_FUNCE_VER			(CIS_FUN1_ADDR + 0x08)
#define FN1_TPL_FUNCE_NSN			(CIS_FUN1_ADDR + 0x0C)
#define FN1_TPL_FUNCE_CSASIZE		(CIS_FUN1_ADDR + 0x10)
#define FN1_TPL_FUNCE_OCR			(CIS_FUN1_ADDR + 0x14)
#define FN1_TPL_FUNCE_MINPWR		(CIS_FUN1_ADDR + 0x18)
#define FN1_TPL_FUNCE_STANDBY		(CIS_FUN1_ADDR + 0x1C)
#define FN1_TPL_FUNCE_OPTBW		    (CIS_FUN1_ADDR + 0x20)
#define FN1_TPL_FUNCE_NTIMEOUT	    (CIS_FUN1_ADDR + 0x24)
#define FN1_TPL_FUNCE_AVGPWR		(CIS_FUN1_ADDR + 0x28)
#define FN1_TPL_END					(CIS_FUN1_ADDR + 0x30)

enum INTERFACE_TYPE
{
	INTERFACE_TYPE_SSPI,			// SLAVE SPI
	INTERFACE_TYPE_SSDIO,			// SLAVE SDIO
};

struct TxBufDesc
{
	volatile uint32_t valid_ctrl;
	uint32_t buf_info;
	uint32_t buf_addr[3];
	uint32_t next;
};

struct RxBufDesc
{
	uint32_t valid_ctrl;
	uint32_t buf_addr;
	uint32_t next;
};

typedef struct __SSPI_HandleTypeDef
{
	SSPI_TypeDef                *Instance1;      /*!< SSPI registers base address               */
	
	SSDIO_TypeDef				*Instance2;		 /*!< SSDIO registers base address              */
	
	WRAPPER_TypeDef				*Instance3;      /*!< WRAPPER registers base address            */
	
	struct TxBufDesc 			*TxDesc;		 /*!< Current tx data descriptor address            */
	
	struct RxBufDesc			*RxDesc;		 /*!< Current rx data descriptor address            */
	
	uint8_t 					*RxCmdBuf;		 /*!< Rx cmd buf address            */
	
	uint8_t					    *cis;			 /*!< SSDIO CIS ADDRESS            */
	
	HAL_LockTypeDef             Lock;           /*!< Locking object                           */

} SSPI_HandleTypeDef;

typedef struct __CIS_FN0_TypeDef
{
	uint32_t FUNCID;
	uint32_t FUNCE;
	uint32_t FUNCE_MAXBLK;
	uint32_t MANFID_MID;
	uint32_t END;
} CIS_FN0_TypeDef;

typedef struct __CIS_FN1_TypeDef
{
	uint32_t FUNCID;
	uint32_t FUNCE;
	uint32_t FUNCE_VER;
	uint32_t FUNCE_NSN;
	uint32_t FUNCE_CSASIZE;
	uint32_t FUNCE_OCR;
	uint32_t FUNCE_MINPWR;
	uint32_t FUNCE_STANDBY;
	uint32_t FUNCE_OPTBW;
	uint32_t FUNCE_NTIMEOUT;
	uint32_t FUNCE_AVGPWR1;
	uint32_t FUNCE_AVGPWR2;
	uint32_t END;
} CIS_FN1_TypeDef;

HAL_StatusTypeDef HAL_SSPI_Init(enum INTERFACE_TYPE type);

HAL_StatusTypeDef HAL_SSPI_DeInit(void);

void HAL_SSPI_MspInit(void);

void HAL_SSPI_MspDeInit(void);

HAL_StatusTypeDef HAL_SSPI_Transmit(uint8_t *pData, uint32_t Size);

void HAL_SSPI_IRQHandler(void);

void HAL_SSPI_RxCmdCpltCallback(uint8_t *buf);

void HAL_SSPI_TxCpltCallback(void);

void HAL_SSPI_RxDataCpltCallback(uint8_t *buf);

#endif